<?

/**
*Form Builder & Admin Generator

*@author marcio <opi14@op.pl>, <polishvodka7@gmail.com>
*@copyright Copyright (c) 2011, marcio
*@version 1.6.5
*/

class Volta_Db_MySql
{

	/**
	*ustawiamy tryb debugowania w przypadku blednego zapytania do bazy
	*@var string $debug dev lub final 
	*@access protected
	*/
	protected $debug = 'dev'; //final
	
	/**
	*skladowa przechowywuje polaczenie z baza
	*@var int|null $connection
	*@access protected
	*/
	protected $connection = null;
  
	/**
	*trzyma rezultat zapytan sql po fetch*
	*@var array $assoc
	*@access protected
	*/
	protected $assoc = array();
  
 	/**
	*Zapytanie do bazy danych
	*@var string $query 
	*@access protected
	*/
	protected $query = '';

	/**
	*skladowa do profilowania zapytan sql gdy wystapi blad
	*@var array $queriesperf
	*@access protected
	*@static
	*/
	protected static $queriesperf = array();
	
	/**
	*konfiguracja dla polaczenia bazy danych
	*@var object $config
	*@access private
	*/
	private $config;
  
  
	/**
	*Inicjalizuje polaczenie z baza, wybiera baze i ustawia kodowanie
	*@access public 
	*@return mixed $this -> connection handler polaczenia
	*/
	public function __construct() 
	{
		$this -> config = Loader::load('Cfg');
		self::$queriesperf['all_queries'] = 0;
  
		if($this -> connection = mysql_connect($this -> config -> host, $this -> config -> login, $this -> config -> pwd)) 
		{
			if(!mysql_select_db($this -> config -> db))
				throw new Volta_Mysql_Adapter_Exception('Wystapil problem podczas wybierania bazy: '.$this -> config -> db);
		
			if(!empty($this -> config -> charset)) 
				$this -> SetCharset($config -> charset);
		
			return $this -> connection;
		}

		else
			throw new Volta_Mysql_Adapter_Connection_Exception("Wystapil blad podczas laczenia z baza:");
	}
 
	/**
	*Ustawia kodowanie
	*@access public 
	*@param string $charset typ kodowania
	*/
	public function SetCharset($charset) 
	{
		$this -> SetQuery('SET NAMES '.$this -> Escape($charset));
	}
 
 
	/**
	*Filtruje dane 
	*@access protected
	*@param string $escape dane do filtrowania
	*@return mixed przefiltrowane dane
	*/
	protected function Escape($escape) 
	{
		switch($escape) 
		{
			case is_string($escape):
									return "'" . mysql_real_escape_string($escape) . "'";
									break;
							 
			case is_int($escape)   :
									return (int)$escape;
									break;
									
			case is_float($escape)   :
									return (float)$escape;
									break;
				
			default                :
									return "'" . $escape . "'";
									break;
	
		} 
	}
 

	/**
	*Tworzy funkcje dla aliasow
	*@access protected
	*@param string $func funkcja dla aliasu (max, min, count)
	*@param string $column kolumna ktora ma byc wykorzystana do aliasu
	*@param bool $as tworzy alias gdy true
	*@return string kawalek zapytania sql 
	*/
	protected function CallBackFunc($func = '', $column, $as = false) 
	{
		if(!empty($func)) 
		{
			if($as) 
				$callback = "$func($column) AS var"; 
			else 
				$callback = "$func($column)";
		  
		}
		return $callback;
	}
 
 
	/**
	*Wykonuje zapytanie
	*@access public 
	*@param string $query zapytanie sql do wykonania
	*@return mixed handler zapytania
	*/
	public function SetQuery($query) 
	{
		$sql = mysql_query($query);
		
		if($sql === false)
			throw new Volta_Mysql_Adapter_Query_Exception(mysql_error(), mysql_errno(), $query, self::$queriesperf, $this -> debug);
			
		return $sql;
	}
  
 
	/**
	*Tworzy czesc zapytania dla select
	*@access public 
	*@param string $rows kolumny
	*@param string $table tabela z ktorej pobrac dane
	*@param string $callbackFunc funkcja dla aliasu
	*@param bool $callbackAs czy ma tworzy alias lub nie
	*@return object $this
	*/
	public function Select($rows, $table, $callbackFunc = '', $callbackAs = true) 
	{
		$select = 'SELECT ';
	
		if(is_string($rows) && isset($callbackFunc)) 
		{
			if(!empty($callbackFunc)) 
			{
				if($callbackAs) 
					$selectCall = $this -> CallBackFunc($callbackFunc, $rows, true); 
				else
					$selectCall = $this -> CallBackFunc($callbackFunc, $rows, false);  
			}
	   
			else
				$selectCall = $rows;
	   
			$select .= $selectCall;
		}
	
		else if(is_array($rows) && count($rows) > 1)
			$select .= implode(',', $rows);
		else if(is_string($rows))
			$select .= $rows;
	
		$select .= ' FROM ';
		$select .= (is_array($table)) ? implode(',', $table): $table;
		$this -> query .= $select;
		
		return $this;;
	}
  
  
	/**
	*Tworzy czesc zapytania dla join
	*@access public 
	*@param string $table tabela
	*@param string $on warunki dla join'a
	*@param string $cond typ join'a
	*@return object $this
	*/
	public function Join($table, $on, $cond = 'INNER') 
	{
  
		if(in_array($cond, array('JOIN', 'INNER', 'LEFT', 'RIGHT', 'OUTER', 'LEFT OUTER', 'RIGHT OUTER', 'FULL OUTER')))
			$join = ($cond == 'JOIN') ? ' '.$cond.' ': ' '.$cond.' JOIN ';
		else
			$join = ' INNER JOIN '.$table;
	
		$join .= (is_array($table)) ? implode(',', $table): $table;
	
		if(is_array($on)) 
		{
			$join .= ' ON(';
	
			foreach($on as $column => $equalColumn) 
				$onClause[] = $column.'='.$equalColumn;
	  
			$join .= implode(' ', $onClause);
			$join .= ')';
		}
	
		else if(is_string($on)) 
			$join .= ' USING('.$on.')';
	
		$this -> query .= $join;
		return $this;
	}
  

	/**
	*Tworzy czesc zapytania dla where +and+
	*@access public 
	*@param string $where warunki where
	*@return object $this
	*/
	public function Where($where = array()) 
	{
		$whr = ' WHERE ';
  
		if(is_array($where) && count($where) > 0) 
		{
			foreach($where as $name => $value) 
			{
				if(!strstr($name, '='))
					$data[] = $name.'='.$this -> Escape($value);
				else if(strstr($name, '='))
					$data[] = $name.$this -> Escape($value);
			}	
		}
		
		$whr .= implode(' and ', $data);
		$this -> query .= $whr;
	
		return $this;
	}
  
  
	/**
	*Tworzy czesc zapytania dla where +or+
	*@access public 
	*@param string $where warunki
	*@return object $this
	*/
	public function WhereOr($where = array()) 
	{
		$whr = ' WHERE ';
  
		if(is_array($where) && count($where) > 0) 
		{
			foreach($where as $name => $value) 
			{
	  
				if(!strstr($name, '='))
					$data[] = $name.'='.$this -> Escape($value);
				else if(strstr($name, '='))
					$data[] = $name.$this -> Escape($value);
			}
		}
	
		$whr .= implode(' or ', $data);
		$this -> query .= $whr;
	
		return $this;
	}
  
  
	/**
	*Tworzy czesc zapytania dla sortowania
	*@access public 
	*@return object $this
	*/
	public function OrderBy() 
	{
		if(func_num_args() == 0)
			$orderBy = ' ORDER BY RAND()';
	
		else if(func_num_args() == 1) 
		{
			$orderBy = ' ORDER BY ';
			$argv = func_get_args();
			$argv = $argv[0];
	  
			if(is_array($argv))
			{
				foreach($argv as $column => $ord) 
				{
					$ord = strtoupper($ord);
		
					if(!in_array($ord, array('ASC', 'DESC', 'NULL')))
						$ord = 'ASC';
			
					$ordColumn[] = $column.' '.$ord;
				}

				$orderBy .= implode(',', $ordColumn);
			}  
		}
	
		else if(func_num_args() == 2) 
		{
			$argv = func_get_args();
			$orderBy = ' ORDER BY '.$argv[0].' '.strtoupper($argv[1]);
		}
 
		$this -> query .= $orderBy; 
		return $this;
	}
  
  
	/**
	*Tworzy czesc zapytania dla limit
	*@access public 
	*@param int|array $limit limit dla zapytania $obj -> Limit(5) / $obj -> Limit(array(1,10))
	*@return object $this
	*/
	public function Limit($limit) 
	{
 
		$lmt = ' LIMIT ';
		$lmt .= (is_array($limit)) ? implode(',', $limit): $limit;
		$this -> query .= $lmt;
	
		return $this; 
	}
  
  
	/**
	*Tworzy czesc zapytania dla groupby
	*@access public 
	*@param string|array $group warunki
	*@return object $this
	*/
	public function GroupBy($group) 
	{
		$groupSql = ' GROUP BY ';
  
		if(is_array($group)) 
		{
			foreach($group as $groupBy)
				$groupClause[] = $groupBy;
	  
			$groupSql .= implode(',', $groupClause);
		}
	
		else
			$groupSql .= $group;

		$this -> query .= $groupSql;
		return $this;
	}
  
  
	/**
	*Tworzy czesc zapytania dla like
	*@access public 
	*@param array $like warunek like
	*@param bool $not NOT LIKE / LIKE
	*@param string $expression laczenie +and+ / +or+
	*@param string $contain typ szukania *% / %* / %*%
	*@return object $this
	*/
	public function Like($like = array(), $not = false, $expression = 'and', $contain = '%%') 
	{
  
		$likeSql = ' WHERE ';
		$ex = ($expression == 'and') ? ' and ': ' or ';
		$exNot = ($not === true) ? ' NOT LIKE ': ' LIKE ';
		
		if($contain == '%%')
			$search_contain = '%'.$this -> Escape($value).'%';
		else if($contain == '%*')
			$search_contain = '%'.$this -> Escape($value);
		else if($contain == '*%')
			$search_contain = $this -> Escape($value).'%';
			
	
		if(is_array($like) && count($like) > 0) 
		{
			foreach($like as $key => $value) 
				$likes[] = $key.$exNot.$search_contain;
		}
	
		$likeSql .= implode($ex, $likes);
		$this -> query .= $likeSql;
	
		return $this;
	}
  
	/**
	*Tworzy czesc zapytania dla in()
	*@access public 
	*@param string $column kolumna
	*@param array $in wartosci dla warunku in - in(1,2,3)
	*@param bool $clause NOT IN / IN
	*@param array $selectRows kolumna dla warunku in
	*@param array $conf konfiguracja [0]tabela [1]kolumna [2]funkcja dla aliasu [3]alias wlaczony/wylaczony
	*@param array $where warunek where
	*@return object $this
	*/
	public function In($column = '', $in = array(), $clause = false, $selectRows = array(), $conf = array(), $where = array()) 
	{
		$inClause = ($clause == true) ? ' NOT IN' : ' IN';
	
		if(count($selectRows) > 0 && count($conf) > 0)	
		{
			$this -> query .= ' WHERE '.$conf[1].$inClause.'(';
	  
			if(isset($where) && count($where) > 0) 
			{
				$this -> Select($selectRows, $conf[0], $conf[2], $conf[3]);
				$this -> Where($where);			  
			}
	  
			else 
				$this -> Select($selectRows, $conf[0], $conf[2], $conf[3]);
	
			$this -> query .= ')';
		
		}
	
		else
		{
			foreach($in as $escIn)
				$escapeIn[] = $this -> Escape($escIn);
			
			$this -> query .= ' WHERE '.$column.$inClause.'('.implode(',', $escapeIn).')';
		}
  
		return $this; 
	}
  
  
	/**
	*Wysyla zapytanie do bazy
	*@access public 
	*@return mixed $result
	*/
	public function Execute() 
	{	 
		$qid = $this -> start();
		
		if($result = $this -> SetQuery($this -> query)) 
		{
			$this -> reset_query();
			$this -> stop($qid);
	    }
		
		return $result;
	}
  
  
	/**
	*Zapytanie insert
	*@access public 
	*@param string $table tabela do ktorej zapisac dane
	*@param array $records rekordy w postaci array('pole' => 'wartosc')
	*@param bool $into czy ma byc czesc dla into (wtedy trzeba uwazac na taka sama kolejnosc zmiennych jak w bazie
	*@return mixed
	*/
	public function Insert($table, $records = array(), $into = false)
	{
		$insert = 'INSERT INTO '.$table;
	
		if(is_array($records) && count($records >= 0)) 
		{
			if($into)
			{
				$insert .= '(';
	
				foreach($records as $column => $record)
					$insCol[] = "`$column`";
		 
				$insert .= implode(',', $insCol);	 
				$insert .= ')';
			}
	 
			$insert .= ' values(';
	  
			foreach($records as $column => $record)
				$insRec[] = $this -> Escape($record);
	  
			$insert .= implode(',', $insRec);
			$insert .= ')';
	
		}
		
		return $this -> SetQuery($insert);
	}
  
  
	/**
	*zapytanie typu delete
	*@access public 
	*@param string $table tabela z ktorej usunac
	*@param array $where warunek where dla ktorego trzeba usunac rekord
	*@return mixed
	*/
	public function Delete($table, $where = array()) 
	{
		$delete = 'DELETE FROM '.$table.' WHERE ';
	
		if(is_array($where) && count($where) >= 1) 
		{
			foreach($where as $key => $value)
				$del[] = $key.'='.$this -> Escape($value);
		}
	
		$delete .= implode(' and ', $del);
	
		return $this -> SetQuery($delete);
	}
  
  
	/**
	*zapytanie typu update
	*@access public 
	*@param string $table tabela
	*@param array $set wartosci rekordow array('kolumna' => 'wartosc')
	*@param array $where warunek dla zapytania
	*@return mixed
	*/
	public function Update($table, $set = array(), $where = array()) 
	{
		if(is_array($set) && count($set) >= 1) 
		{
			foreach($set as $key => $val)
				$setValue[] = $key.'='.$this -> Escape($val);
		}
	
		$column = array_keys($where);
		$value = $this -> Escape($where[$column[0]]);
		$update = 'UPDATE '.$table.' SET '.implode(',', $setValue).' WHERE '.$column[0].'='.$value;
	
		return $this -> SetQuery($update);
	}

	
	/**
	*liczy ilosc rekordow
	*@access public 
	*@param resource $resource
	*@return int
	*/
	public function CountRows($resource)
	{
		$rows = mysql_num_rows($resource);
		
		if(!$rows)
			throw new Volta_Mysql_Adapter_Exception('Blad podczas mysql_num_rows().');
			
		return $rows;
	}

	
	/**
	*zwraca rekordy w postaci tablicy
	*@access public 
	*@param resource $resource
	*@return array
	*/
	public function FetchAllAssoc($resource) 
	{
		while($tab = mysql_fetch_assoc($resource))
			$data[] = $tab;
   
		return $data;
	}
  

	/**
	*zwraca rekord w postaci tablicy
	*@access public 
	*@param resource $resource
	*@return array
	*/
	public function FetchAssoc($resource) 
	{
		return mysql_fetch_assoc($resource);
	}
	

	/**
	*zwraca rekord w postaci tablicy z kluczami numerycznymi
	*@access public 
	*@param resource $resource
	*@return array
	*/
	public function FetchRow($resource) 
	{
		return mysql_fetch_row($resource);
	}


	/**
	*zwraca rekordy w postaci tablicy
	*@access public 
	*@param resource $resource
	*@return array
	*/
	public function FetchAllRows($resource) 
	{
		while($tab = mysql_fetch_row($resource)) 
		{
			foreach($tab as $key => $value) 
				$this -> assoc[$key] = $value;
		}

		return $this -> assoc;
	}
  

 	/**
	*profiler uwzglednia poczatkowy czas zapytania i jego "tresc", zwieksza licznkin lacznych zapytan
	*@access protected
	*@return string $qid id zapytania
	*/
	protected function start()
	{
		if($this -> debug == 'dev') 
		{
			$qid = uniqid();
			self::$queriesperf['all_queries']++;
			self::$queriesperf[$qid]['query'] = $this -> query;
			self::$queriesperf[$qid]['init_time'] = microtime();
			return $qid; 
		}
	}
	
	
	/**
	*zatrzymuje profilowanie dla danego zapytania
	*@access public 
	*@param string $qid id zapytania
	*/
	protected function stop($qid)
	{
		if($this -> debug == 'dev') 
		{
			self::$queriesperf[$qid]['time'] = number_format(microtime() - self::$queriesperf[$qid]['init_time'], 6);
			self::$queriesperf['all_time'] += self::$queriesperf[$qid]['time'];
		}
	}
  

	/**
	*czysci skladowa z zapytaniem
	*@access protected 
	*/
	protected function reset_query()
	{
		$this -> query = '';
	}


	/**
	*zamyka polaczenie z baza
	*@access public 
	*/
	public function __destruct() 
	{
		if(is_resource($this -> conn)) 
			mysql_close($this -> conn);
	}
}

?>